package novel

import (
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/flipped-aurora/gin-vue-admin/server/global"
	"github.com/flipped-aurora/gin-vue-admin/server/model/novel"
	"github.com/flipped-aurora/gin-vue-admin/server/utils"
	"go.uber.org/zap"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	base         = "https://www.ibookben.com"
	source       = "bb"
	search       = "https://www.ibookben.com/search/"
	downloadPage = "https://www.ibookben.com/txt/%s.html"
	readPage     = "https://www.ibookben.com/read/%s/"
)

var NumRegexp, _ = regexp.Compile("\\d+")

var BaseHeader = http.Header{
	"Content-Type": []string{"application/x-www-form-urlencoded"},
	"origin":       []string{"https://www.ibookben.com"},
}

// 书本网 解析
type BookBen struct {
}

func (b BookBen) ChapterByAuthorAndName(author string, name string, id string) (*novel.BookChapters, error) {
	cacheKey := fmt.Sprintf("detail:bookBen:author:%s:name:%s", author, id)
	chapters, ok := global.BlackCache.Get(cacheKey)
	global.GVA_LOG.Info("[缓存去章节信息]: ",
		zap.Bool("ok", ok), zap.Any("chapters", chapters), zap.String("name", name), zap.String("author", author))
	if ok {
		chapter := chapters.(novel.BookChapters)
		return &chapter, nil
	}
	bookLists, _ := b.SearchByName(name)
	global.GVA_LOG.Info("bookList: ", zap.Any("bookList", bookLists))
	if len(bookLists) > 0 {
		for _, book := range bookLists {
			if strings.Contains(book.Author, author) && strings.Contains(book.Title, name) {

				chapters, _ := b.ChapterByAuthorById(book.Id)
				chapters.Id = id
				global.BlackCache.Set(cacheKey, *chapters, time.Hour*12)
				return chapters, nil
			}
		}
	}
	return nil, nil
}

func (b BookBen) SearchByName(name string) ([]novel.BillBook, error) {

	// 同步请求
	requestStr := url.PathEscape(fmt.Sprintf("searchkey=%s", name))
	header := utils.CloneStrArrMap(BaseHeader)
	html, err := GetDocument("POST", search, requestStr, header)
	if err != nil {
		return nil, err
	}
	bookListSelector := html.Find("dl")
	if nil != bookListSelector && len(bookListSelector.Nodes) > 0 {

		bookLists := make([]novel.BillBook, 0)
		first := bookListSelector.First()
		for i := 0; i < bookListSelector.Length(); i++ {
			bookAttr := first.Find("dt")
			if bookAttr == nil {
				continue
			}
			billBook := novel.BillBook{}
			book := bookAttr.First()
			billBook.Title = book.Text()
			billBook.Site = source
			a := book.Find("a")
			if a != nil {
				attr, exists := a.Attr("href")
				if exists {
					billBook.Id = utils.GroupFirstStr(NumRegexp, attr, 0)
				}
			}
			for i := 0; i < first.Children().Size(); i++ {
				text := book.Text()
				if strings.Contains(text, "类别：") {
					billBook.Cat = strings.Replace(text, "类别：", "", 1)
				} else if strings.Contains(text, "作者：") {
					billBook.Author = strings.Replace(text, "作者：", "", 1)

				}
				//else if strings.Contains(text, "字数：") {
				//	//billBook.Author = strings.Replace(text, "字数：", "", 1)
				//
				//} else if strings.Contains(text, "更新：") {
				//
				//} else if strings.Contains(text, "全本下载") {
				//
				//} else if strings.Contains(text, "在线阅读") {
				//
				//}
				book = book.Next()

			}
			first = first.Next()
			bookLists = append(bookLists, billBook)
		}
		return bookLists, err
	}
	return nil, err

}

func (b BookBen) DetailById(id string) (*novel.BookDetail, error) {

	cacheKey := "detail:bookBen:" + id
	detailCache, ok := global.BlackCache.Get(cacheKey)
	if ok {
		detail := detailCache.(novel.BookDetail)
		return &detail, nil
	}
	urlStr := fmt.Sprintf(readPage, id)
	strMap := utils.CloneStrArrMap(BaseHeader)
	document, err := GetDocument("GET", urlStr, "", strMap)
	if err != nil {
		return nil, err
	}
	detail := novel.BookDetail{}
	detail.Id = id
	infoNode := document.Find(".yxjj")
	if infoNode != nil {
		children := infoNode.Children()
		if children != nil {
			name := children.First()
			cat := name.Next()
			author := cat.Next()
			status := author.Next()
			word := status.Next()
			updated := word.Next()
			detail.Title = name.Text()
			detail.Cat = strings.Replace(cat.Text(), "小说类别：", "", 1)
			detail.Author = strings.Replace(author.Text(), "作者：", "", 1)
			count, _ := strconv.Atoi(strings.Replace(author.Text(), "字数：", "", 1))
			detail.WordCount = count
			if updated != nil {
				date, err := time.Parse("2006-01-02 15:04:05", strings.Replace(updated.Text(), "更新日期：", "", 1))
				if nil == err {
					detail.Updated = ParseTDate(date)
				}
			}
			descNode := document.Find(".xgjsdd")
			if document != nil {
				detail.LongIntro = descNode.Text()
			}

		}

	}
	coverNode := document.Find(".ebookpic>img")

	if coverNode != nil {
		attr, exists := coverNode.Attr("src")
		if exists {
			detail.Cover = attr
		}
	}
	global.BlackCache.Set(cacheKey, detail, time.Hour*12)
	return &detail, err
}

func (b BookBen) ChapterByAuthorById(id string) (*novel.BookChapters, error) {
	cacheKey := "chapters:bookBen:" + id
	chapters, ok := global.BlackCache.Get(cacheKey)
	if ok {
		bookChapters := chapters.(novel.BookChapters)
		return &bookChapters, nil
	}
	urlStr := fmt.Sprintf(readPage, id)
	strMap := utils.CloneStrArrMap(BaseHeader)
	document, err := GetDocument("GET", urlStr, "", strMap)
	if err != nil {
		return nil, err
	}
	chaptersNode := document.Find(".n>a")
	if chaptersNode != nil {
		chapters := make([]novel.BookChapter, 0)
		bookChapters := novel.BookChapters{Id: id, Book: id}
		chaptersNode.Each(func(i int, selection *goquery.Selection) {
			chapterName := selection.Text()
			urlStr, exists := selection.Attr("href")
			if exists && len(chapterName) > 0 {
				chapters = append(chapters, novel.BookChapter{Title: chapterName, Link: urlStr, Unreadble: "false"})
			}
		})

		updateTime := document.Find("dl.yxjj > dd:nth-child(6)")
		if updateTime != nil {
			date, err := time.Parse("2006-01-02 15:04:05", strings.Replace(updateTime.Text(), "更新日期：", "", 1))
			if nil == err {
				bookChapters.Updated = ParseTDate(date)
			}
		}
		bookChapters.Chapters = chapters
		bookChapters.ChaptersCount1 = int32(len(chapters))
		global.BlackCache.Set(cacheKey, bookChapters, time.Hour*12)
		return &bookChapters, err
	}
	return &novel.BookChapters{Id: id, Book: id, ChaptersCount1: 1,
		Chapters: EmptyChapterList}, nil
}

func (b BookBen) DownloadByUrl(url string) {

}

func (b BookBen) ContentByUrl(urlStr string) (*novel.ChapterInfo, error) {
	if EmptyContentChapter == urlStr {
		return &novel.ChapterInfo{Title: "无章节信息", Body: EmptyChapterContent}, nil
	}
	urlStr = base + urlStr
	chapterInfos := make([]novel.ChapterInfo, 0)
	for {

		strMap := utils.CloneStrArrMap(BaseHeader)
		document, err := GetDocument("GET", urlStr, "", strMap)
		if err != nil {
			return &novel.ChapterInfo{Title: "无章节信息", Body: EmptyChapterContent}, err
		}
		info := novel.ChapterInfo{}
		contentNode := document.Find("#content>p")
		if contentNode != nil {
			var content string
			contentNode.Each(func(i int, selection *goquery.Selection) {
				content += selection.Text() + "\n"
			})
			//info.Body = contentNode.Text()
			info.Body = content
		}
		titleNode := document.Find("#headline")
		if titleNode != nil {
			info.Title = titleNode.Text()
		}
		chapterInfos = append(chapterInfos, info)

		nextUrlNode := document.Find("#next_url")
		if nil != nextUrlNode {
			attr, exists := nextUrlNode.Attr("href")
			if exists && "下一页" == nextUrlNode.First().Text() {
				urlStr = base + attr
			} else {
				break
			}
		}
	}
	// 合并
	merge := novel.ChapterInfo{}
	for _, v := range chapterInfos {
		merge.Title = v.Title
		merge.Body = merge.Body + v.Body
	}
	return &merge, nil
}
